package com.powernode.customer.service.impl;

import com.powernode.common.execption.PowerException;
import com.powernode.common.result.ResultCodeEnum;
import com.powernode.customer.service.OrderService;
import com.powernode.dispatch.client.NewOrderFeignClient;
import com.powernode.driver.client.DriverInfoFeignClient;
import com.powernode.map.client.LocationFeignClient;
import com.powernode.map.client.MapFeignClient;
import com.powernode.model.entity.order.OrderInfo;
import com.powernode.model.form.customer.ExpectOrderForm;
import com.powernode.model.form.customer.SubmitOrderForm;
import com.powernode.model.form.map.CalculateDrivingLineForm;
import com.powernode.model.form.order.OrderInfoForm;
import com.powernode.model.form.rules.FeeRuleRequestForm;
import com.powernode.model.vo.customer.ExpectOrderVo;
import com.powernode.model.vo.dispatch.NewOrderTaskVo;
import com.powernode.model.vo.driver.DriverInfoVo;
import com.powernode.model.vo.map.DrivingLineVo;
import com.powernode.model.vo.map.OrderLocationVo;
import com.powernode.model.vo.map.OrderServiceLastLocationVo;
import com.powernode.model.vo.order.CurrentOrderInfoVo;
import com.powernode.model.vo.order.OrderInfoVo;
import com.powernode.model.vo.rules.FeeRuleResponseVo;
import com.powernode.order.client.OrderInfoFeignClient;
import com.powernode.rules.client.FeeRuleFeignClient;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.Date;

/**
 * 订单服务实现类
 * 处理订单相关的业务逻辑，包括计算订单费用、查询订单等
 */
@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class OrderServiceImpl implements OrderService {
    @Resource
    private MapFeignClient mapFeignClient;//地图服务Feign客户端
    @Resource
    private FeeRuleFeignClient feeRuleFeignClient;//费用规则服务Feign客户端
    @Resource
    private OrderInfoFeignClient orderInfoFeignClient;//订单服务Feign客户端
    @Resource
    private NewOrderFeignClient newOrderFeignClient;//新订单服务Feign客户端
    @Resource
    private DriverInfoFeignClient driverInfoFeignClient;//配送员服务Feign客户端
    @Resource
    private LocationFeignClient locationFeignClient;//位置服务Feign客户端

    /**
     * 预估订单
     *
     * @param expectOrderForm 期望订单表单
     * @return 预估订单信息
     */
    @Override
    public ExpectOrderVo expectOrder(ExpectOrderForm expectOrderForm) {
        // 创建计算行驶路线表单对象
        CalculateDrivingLineForm calculateDrivingLineForm = new CalculateDrivingLineForm();
        // 复制属性从期望订单表单到计算行驶路线表单
        BeanUtils.copyProperties(expectOrderForm, calculateDrivingLineForm);
        // 调用地图服务计算行驶路线
        DrivingLineVo drivingLineVo = mapFeignClient.calculateDrivingLine(calculateDrivingLineForm).getData();

        // 创建费用规则请求表单
        FeeRuleRequestForm feeRuleRequestForm = new FeeRuleRequestForm();
        // 设置行驶距离
        feeRuleRequestForm.setDistance(drivingLineVo.getDistance());
        // 设置开始时间为当前时间
        feeRuleRequestForm.setStartTime(new Date());
        // 设置等待时间为0分钟
        feeRuleRequestForm.setWaitMinute(0);
        // 调用费用规则服务计算订单费用
        FeeRuleResponseVo feeRuleResponseVo = feeRuleFeignClient.calculateOrderFee(feeRuleRequestForm).getData();

        // 创建期望订单返回对象
        ExpectOrderVo expectOrderVo = new ExpectOrderVo();
        // 设置行驶路线信息
        expectOrderVo.setDrivingLineVo(drivingLineVo);
        // 设置费用规则响应信息
        expectOrderVo.setFeeRuleResponseVo(feeRuleResponseVo);

        return expectOrderVo;
    }

    /**
     * 添加订单
     *
     * @param submitOrderForm 提交订单表单
     * @return 订单ID
     */
    @Override
    public Long addOrder(SubmitOrderForm submitOrderForm) {
        // 重新计算行驶路线，确保路线信息准确
        CalculateDrivingLineForm calculateDrivingLineForm = new CalculateDrivingLineForm();
        // 复制属性从提交订单表单到计算行驶路线表单
        BeanUtils.copyProperties(submitOrderForm, calculateDrivingLineForm);
        // 调用地图服务Feign客户端计算行驶路线
        DrivingLineVo drivingLineVo = mapFeignClient.calculateDrivingLine(calculateDrivingLineForm).getData();

        // 创建费用规则请求表单
        FeeRuleRequestForm feeRuleRequestForm = new FeeRuleRequestForm();
        // 设置等待时间为0分钟
        feeRuleRequestForm.setWaitMinute(0);
        // 设置行驶距离（从路线计算结果获取）
        feeRuleRequestForm.setDistance(drivingLineVo.getDistance());
        // 设置开始时间为当前时间
        feeRuleRequestForm.setStartTime(new Date());
        // 调用费用规则服务Feign客户端计算订单费用
        FeeRuleResponseVo feeRuleResponseVo = feeRuleFeignClient.calculateOrderFee(feeRuleRequestForm).getData();

        // 创建订单信息表单
        OrderInfoForm orderInfoForm = new OrderInfoForm();
        // 复制属性从提交订单表单到订单信息表单
        BeanUtils.copyProperties(submitOrderForm, orderInfoForm);
        // 设置预期行驶距离
        orderInfoForm.setExpectDistance(drivingLineVo.getDistance());
        // 设置预期订单金额
        orderInfoForm.setExpectAmount(feeRuleResponseVo.getTotalAmount());

        // 调用订单服务Feign客户端添加订单信息
        Long orderId = orderInfoFeignClient.addOrderInfo(orderInfoForm).getData();
        //启动定时任务 搜索附近符合条件的配送员
        //创建新订单任务Vo对象，用于封装定时任务所需的订单信息
        NewOrderTaskVo newOrderTaskVo = new NewOrderTaskVo();
        //使用BeanUtils将订单表单对象的属性复制到任务Vo对象中
        BeanUtils.copyProperties(orderInfoForm, newOrderTaskVo);

        //设置订单ID，从订单服务返回的结果中获取
        newOrderTaskVo.setOrderId(orderId);
        //设置期望送达时间，使用之前计算的路线持续时间
        newOrderTaskVo.setExpectTime(drivingLineVo.getDuration());
        //设置任务创建时间为当前时间
        newOrderTaskVo.setCreateTime(new Date());

        //添加并启动定时任务，通过feign客户端调用远程服务
        //该任务将在指定时间后执行，用于搜索附近符合条件的配送员
        newOrderFeignClient.addAndStartTask(newOrderTaskVo).getData();
        return orderId;
    }

    /**
     * 查询订单状态
     *
     * @param orderId 订单ID
     * @return 订单状态
     */
    @Override
    public Integer queryOrderStatus(Long orderId) {
        return orderInfoFeignClient.getOrderStatus(orderId).getData();
    }

    /**
     * 查询顾客当前进行中的订单
     *
     * @param customerId 顾客ID
     * @return 顾客当前进行中的订单信息
     */
    @Override
    public CurrentOrderInfoVo searchCustomerCurrentOrder(Long customerId) {
        return orderInfoFeignClient.searchCustomerCurrentOrder(customerId).getData();
    }

    /**
     * 根据订单ID和客户ID获取订单详情信息
     * 该方法会验证当前客户是否有权限查看指定订单
     *
     * @param orderId    订单ID，用于查询具体的订单信息
     * @param customerId 客户ID，用于验证订单所有权
     * @return OrderInfoVo 订单信息视图对象，包含订单的详细信息
     * @throws PowerException 当客户尝试访问不属于自己的订单时抛出非法请求异常
     */
    @Override
    public OrderInfoVo getOrderInfo(Long orderId, Long customerId) {
        // 通过Feign客户端调用订单服务，获取订单详细信息
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();
        // 权限校验：确保当前客户只能查看自己的订单，比较订单所属客户ID与传入的客户ID是否一致
        if (orderInfo.getCustomerId().longValue() != customerId.longValue()) {
            // 如果不一致，抛出非法请求异常
            throw new PowerException(ResultCodeEnum.ILLEGAL_REQUEST);
        }

        // 创建订单信息视图对象（VO），用于封装返回给前端的数据
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        // 使用BeanUtils工具将orderInfo的属性值复制到orderInfoVo中
        // 这一步会自动映射同名属性
        BeanUtils.copyProperties(orderInfo, orderInfoVo);
        // 显式设置订单ID，确保ID正确设置
        orderInfoVo.setOrderId(orderId);

        // 返回封装好的订单信息视图对象
        return orderInfoVo;
    }

    /**
     * 根据订单ID和客户ID获取司机信息
     * 此方法用于客户查看指定订单的司机信息，包含权限验证逻辑
     *
     * @param orderId    订单ID
     * @param customerId 客户ID
     * @return 司机信息VO对象，包含司机基本信息
     * @throws PowerException 当客户试图查看不属于自己的订单时抛出异常
     */
    @Override
    public DriverInfoVo getDriverInfo(Long orderId, Long customerId) {
        // 调用订单服务获取订单详情
        OrderInfo orderInfo = orderInfoFeignClient.getOrderInfo(orderId).getData();
        // 验证当前客户是否为该订单的所有者（防止越权访问）
        if (orderInfo.getCustomerId().longValue() != customerId.longValue()) {
            // 非订单所属客户请求，抛出非法请求异常
            throw new PowerException(ResultCodeEnum.ILLEGAL_REQUEST);
        }
        // 权限验证通过后，根据订单中的司机ID获取司机信息
        DriverInfoVo driverInfoVo = driverInfoFeignClient.getDriverInfoOrder(orderInfo.getDriverId()).getData();
        // 返回司机信息供前端展示
        return driverInfoVo;
    }

    /**
     * 顾客获取缓存中订单的位置信息
     *
     * @param orderId 订单ID
     * @return 订单位置信息
     */
    @Override
    public OrderLocationVo getCacheOrderLocation(Long orderId) {
        return locationFeignClient.getCacheOrderLocation(orderId).getData();
    }

    /**
     * 计算驾驶路线
     *
     * @param calculateDrivingLineForm 计算驾驶路线表单
     * @return 驾驶路线信息
     */
    @Override
    public DrivingLineVo calculateDrivingLine(CalculateDrivingLineForm calculateDrivingLineForm) {
        return mapFeignClient.calculateDrivingLine(calculateDrivingLineForm).getData();
    }

    /**
     * 获取配送员最后的位置信息
     *
     * @param orderId 订单ID
     * @return 配送员最后的位置信息
     */
    @Override
    public OrderServiceLastLocationVo getOrderServiceLastLocation(Long orderId) {
        return locationFeignClient.getOrderServiceLastLocation(orderId).getData();
    }
}
